﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace DownloadCore
{
    public class DownloadService
    {
        private string downloadUrl = "";//文件下载地址
        private string filePath = "";//文件保存路径
        private string method = "";//方法
        private long fromIndex = 0;//开始下载的位置
        private long toIndex = 0;//结束下载的位置
        private long count = 0;//总大小
        private long size = 524288;//每次下载大小 512kb
        private bool isRun = false;//是否正在进行


        public bool isFinish { get; private set; } = false;//是否已下载完成
        public bool isStopped { get; private set; } = true;//是否已停止


        public event Action OnStart;
        public event Action OnDownload;
        public event Action OnFinish;

        public long GetDownloadedCount()
        {
            return this.count - this.toIndex + this.fromIndex - 1;
        }

        public void Stop()
        {
            this.isRun = false;
        }
        public bool Start(TaskInfo info,bool isReStart)
        {
            this.downloadUrl = info.downloadUrl;
            this.fromIndex = info.fromIndex;
            this.toIndex = info.toIndex;
            this.method = info.method;
            this.filePath = info.filePath;
            this.count = info.count;
            this.isStopped = false;
            if (File.Exists(this.filePath))
            {
                if(isReStart)
                {
                    File.Delete(this.filePath);
                    File.Create(this.filePath).Close();
                }
            }
            else
            {
                File.Create(this.filePath).Close();
            }
            using (var file = File.Open(this.filePath, FileMode.Open))
            {
                this.fromIndex = info.fromIndex+file.Length;
            }
            if(this.fromIndex>=this.toIndex)
            {
                OnFinishHandler();
                this.isFinish = true;
                this.isStopped = true;
                return false;
            }
            OnStartHandler();
            this.isRun = true;
            new Action(() =>
            {
                WebResponse rsp;
                while (this.fromIndex < this.toIndex && isRun)
                {
                    long to;
                    if (this.fromIndex + this.size >= this.toIndex - 1)
                        to = this.toIndex - 1;
                    else
                        to = this.fromIndex + size;
                    using (rsp = HttpHelper.Download(this.downloadUrl, this.fromIndex, to, this.method))
                    {
                        Save(this.filePath, rsp.GetResponseStream());
                    }
                }
                if (!this.isRun) this.isStopped = true;
                if (this.fromIndex >= this.toIndex)
                {
                    this.isFinish = true;
                    this.isStopped = true;
                    OnFinishHandler(); 
                }

            }).BeginInvoke(null, null);
            return true;
        }

        private void Save(string filePath, Stream stream)
        {
            try
            {
                using (var writer = File.Open(filePath, FileMode.Append))
                {
                    using (stream)
                    {
                        var repeatTimes = 0;
                        byte[] buffer = new byte[1024];
                        var length = 0;
                        while ((length = stream.Read(buffer, 0, buffer.Length)) > 0 && this.isRun)
                        {
                            writer.Write(buffer, 0, length);
                            this.fromIndex += length;
                            if (repeatTimes % 5 == 0)
                            {
                                OnDownloadHandler();
                            }
                            repeatTimes++;
                        }
                    }
                }
                OnDownloadHandler();
            }
            catch (Exception)
            {
                //异常也不影响
            }
        }

        private void OnStartHandler()
        {
            new Action(() =>
            {
                this.OnStart?.Invoke();
            }).BeginInvoke(null, null);
        }
        private void OnFinishHandler()
        {
            new Action(() =>
            {
                this.OnFinish?.Invoke();
                this.OnDownload?.Invoke();
            }).BeginInvoke(null, null);
        }
        private void OnDownloadHandler()
        {
            new Action(() =>
            {
                this.OnDownload?.Invoke();
            }).BeginInvoke(null, null);
        }
    }
}
